package com.shxzz.easy12306.services.gateway.filter;

import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.shxzz.easy12306.framework.starter.user.constant.UserConstant;
import com.shxzz.easy12306.framework.starter.user.core.UserInfoDTO;
import com.shxzz.easy12306.framework.starter.user.toolkit.JWTUtil;
import lombok.Data;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

/**
 * Token 验证过滤器
 *
 * @author shxzz
 * @create 2024-03-07-11:48
 */
@Component
public class TokenValidateGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenValidateGatewayFilterFactory.Config> {

    /**
     * 注销用户时需要传递 Token
     */
    public static final String DELETION_PATH = "/api/user-service/deletion";

    public TokenValidateGatewayFilterFactory() {
        super(Config.class);
    }


    @Data
    public static class Config {
        private List<String> blackPathPre;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String requestPath = request.getPath().toString();

            if (!isPathInBlackPreList(requestPath, config.getBlackPathPre())) {
                return chain.filter(exchange);
            }

            String token = request.getHeaders().getFirst("Authorization");
            UserInfoDTO userInfo = JWTUtil.parseAccessToken(token);
            if (!validateToken(userInfo)) {
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }

            ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate().headers(httpHeaders -> {
                httpHeaders.set(UserConstant.USER_ID_KEY, userInfo.getUserId());
                httpHeaders.set(UserConstant.USER_NAME_KEY, userInfo.getUsername());
                httpHeaders.set(UserConstant.REAL_NAME_KEY, URLEncoder.encode(userInfo.getRealName(), StandardCharsets.UTF_8));
                if (Objects.equals(requestPath, DELETION_PATH)) {
                    httpHeaders.set(UserConstant.USER_TOKEN_KEY, token);
                }
            }).build();
            return chain.filter(exchange.mutate().request(serverHttpRequest).build());
        };
    }

    /**
     * 验证 token 是否有效
     */
    private boolean validateToken(UserInfoDTO userInfo) {
        return userInfo != null;
    }


    private boolean isPathInBlackPreList(String requestPath, List<String> blackPathPre) {
        if (CollectionUtils.isEmpty(blackPathPre)) {
            return false;
        }
        return blackPathPre.stream().anyMatch(requestPath::startsWith);
    }
}
